package com.wander.rep.service;

import static com.wander.rep.server.CommonUtilities.DEFAULT_SERVER_URL;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.wander.rep.DetailListActivity;
import com.wander.rep.R;
import com.wander.rep.db4o.SingletonHelper;
import com.wander.rep.patient.Patient;

public class UpdateService extends Service {

	private Handler handler = new Handler();

	private ObjectContainer oc;

	public IBinder onBind(Intent intent) 
	{
		return null;
	}

	/*
	 * (non-Javadoc)
	 * @see android.app.Service#onStartCommand(android.content.Intent, int, int)
	 */
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) 
	{
		Log.d("TEST", "Invoked onStartCommand");

		return 0;
	}

	/*
	 * (non-Javadoc)
	 * @see android.app.Service#onCreate()
	 */
	public void onCreate() 
	{
		super.onCreate();
		
		Toast.makeText(getApplicationContext(), "Updating Database", Toast.LENGTH_LONG).show();

		getDB();
		startService();
	}

	/*
	 * Set oc to the Database Instance from Singleton helper
	 */
	private void getDB() 
	{
		oc = SingletonHelper.getInstance(getApplicationContext()).getDatabaseSession();
	}

	/*
	 * Initialise service in new AsyncTask
	 */
	private void startService()
	{           
		// Start network operation on a new thread
		UpdateTask task = new UpdateTask();
		task.execute(new String[] { DEFAULT_SERVER_URL + "/update" });
	}

	/*
	 * UpdateTask class for updating thread
	 */
	private class UpdateTask extends AsyncTask<String, Void, Patient>
	{ 
		@Override
		protected Patient doInBackground(String... arg0) 
		{
			getDB();

			Patient patient = null;

			HttpPost postRequest = new HttpPost(arg0[0]);
			HttpClient httpClient = new DefaultHttpClient();

			try {
				
				// Deserialize Patient object from InputStream
				HttpResponse response = httpClient.execute(postRequest);
				ObjectInputStream in = new ObjectInputStream(response.getEntity().getContent());
				patient = (Patient)in.readObject();

			} catch (ClientProtocolException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			persistDB(patient);
			
			return patient;
		}

		@Override
		protected void onPostExecute(Patient result) {

			closeAll();

			if(result != null)
			{
				generateNotification(getApplicationContext(), "Service has updated database definitions to the latest updates for patient ID=" + result.getId());
			}
			
			stopSelf();
		}
	}    

	/*
	 * Closes ObjectContainer instance
	 */
	private void closeAll() 
	{
		oc.close();
	}

	/*
	 * (non-Javadoc)
	 * @see android.app.Service#onDestroy()
	 */
	public void onDestroy() 
	{
		super.onDestroy();
		oc.close();
		Toast.makeText(this, "Service Stopped", Toast.LENGTH_SHORT).show();
	}

	/*
	 * Updates the patient in DB
	 */
	void persistDB(Patient patient)
	{
		update(patient);
	}

	/*
	 * Checks for similar patient record and updates it to latest profile
	 */
	private void update(Patient patient) 
	{
		ObjectSet<Patient> patients = oc.query(Patient.class);
		for(Patient p : patients)
		{
			if(patient != null && p.getpName().compareTo(patient.getpName()) == 0 && p.getpSurname().compareTo(patient.getpSurname()) == 0)
			{
				oc.delete(p);
			}
		}

		oc.store(patient);
		oc.commit();
	}

	/**
	 * Issues a notification to inform the user that update has completed
	 */
	@SuppressWarnings("deprecation")
	private static void generateNotification(Context context, String message) {
		int icon = R.drawable.good;
		long when = System.currentTimeMillis();
		NotificationManager notificationManager = (NotificationManager)
				context.getSystemService(Context.NOTIFICATION_SERVICE);

		SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");

		Date resultdate = new Date(when);
		String title = "Updated database at " + sdf.format(resultdate);

		Notification notification = new Notification(icon, message, when);

		Intent notificationIntent = new Intent(context, DetailListActivity.class);
		// set intent so it does not start a new activity
		notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
				Intent.FLAG_ACTIVITY_SINGLE_TOP);
		PendingIntent intent =
				PendingIntent.getActivity(context, 0, notificationIntent, 0);
		notification.setLatestEventInfo(context, title, message, intent);
		notification.flags |= Notification.FLAG_AUTO_CANCEL;
		notification.sound = Uri.parse("android.resource://" + context.getPackageName()+ "/" +R.raw.alert_tone);
		notificationManager.notify(0, notification);
	}
}